﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace VideoLink.Utility
{
    /// <summary>
    /// Класс, содержащий некоторые вспомогательные функции
    /// </summary>
    public static class Utils
    {
        /// <summary>
        /// Объект, необзходимый для взаимного исключения потоков, работающих с жестким диском.
        /// Если их не исключать, то экземпляры Stream работают некорректно.
        /// </summary>
        private static object hddLocker = new object();

        /// <summary>
        /// Вывести ошибку с помощью MessageBox
        /// </summary>
        /// <param name="text"></param>
        /// <param name="caption"></param>
        public static void ShowError(string text, string caption)
        {
            MessageBox.Show(text, caption, MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        /// <summary>
        /// Сериализовать объект в указанный файл.
        /// </summary>
        /// <param name="fileName">
        /// Имя файла, в который сохранять
        /// </param>
        /// <param name="obj">
        /// Объект, который сохранять
        /// </param>
        /// <returns>
        /// Для файла после окончания записи в байтах.
        /// </returns>
        public static long Serialize(string fileName, object obj)
        {
            lock (hddLocker)
            {
                var fileLen = 0L;
                var stream = new FileStream(fileName, FileMode.Create);
                try
                {
                    new BinaryFormatter().Serialize(stream, obj);
                }
                finally
                {
                    fileLen = stream.Length;
                    if (stream != null)
                        stream.Close();
                }
                return fileLen;
            }
        }

        /// <summary>
        /// Десериализовать объект из указанного файла
        /// </summary>
        /// <param name="fileName">
        /// Имя файла, содержащего сохранённый объект
        /// </param>
        /// <returns>
        /// Десериализованный объект.
        /// </returns>
        public static object Deserialize(string fileName)
        {
            var fileLen = 0L;
            return Deserialize(fileName, out fileLen);
        }

        /// <summary>
        /// Десериализовать объект из указанного файла.
        /// </summary>
        /// <param name="fileName">
        /// Имя файла, содержащего сохранённый объект.
        /// </param>
        /// <param name="fileLength">
        /// Длина файла, содержащего объект, в байтах.
        /// </param>
        /// <returns>
        /// Десериализованный объект.
        /// </returns>
        public static object Deserialize(string fileName, out long fileLength)
        {
            lock (hddLocker)
            {
                var stream = new FileStream(fileName, FileMode.Open);
                fileLength = stream.Length;
                object res = null;
                try
                {
                    res = new BinaryFormatter().Deserialize(stream);
                }
                finally
                {
                    if (stream != null)
                        stream.Close();
                }
                return res;
            }
        }

        /// <summary>
        /// Записать последовательность байт в файл.
        /// </summary>
        /// <param name="fileName">
        /// Файл, в который записывать.
        /// </param>
        /// <param name="data">
        /// Данные для записи.
        /// </param>
        public static void WriteToFile(string fileName, byte[] data)
        {
            lock (hddLocker)
            {
                var file = new FileStream(fileName, FileMode.Create);

                try { file.Write(data, 0, data.Length); }
                finally { file.Close(); }
            }
        }

        /// <summary>
        /// Прочитать все данные из файла.
        /// </summary>
        /// <param name="fileName">
        /// Имя файла, который будем читать.
        /// </param>
        /// <returns>
        /// Содержимое файла.
        /// </returns>
        public static byte[] ReadAllFromFile(string fileName)
        {
            lock (hddLocker)
            {
                byte[] result = null;
                Stream stream = null;
                try
                {
                    stream = new FileStream(fileName, FileMode.Open);
                    result = new byte[stream.Length];
                    stream.Read(result, 0, (int)stream.Length);
                }
                finally
                {
                    if (stream != null)
                        stream.Close();
                }
                return result;
            }
        }

        /// <summary>
        /// Получить длину файла, не загружая его в память
        /// </summary>
        /// <param name="fileName">Имя файла</param>
        /// <returns>Длина файла</returns>
        public static long GetFileSize(string fileName)
        {
            lock (hddLocker)
            {
                FileStream stream = null;
                long res = 0;

                try
                {
                    stream = new FileStream(fileName, FileMode.Open);
                    res = stream.Length;
                }
                finally
                {
                    if (stream != null)
                        stream.Close();
                }

                return res;
            }
        }
    }
}
